import Bluetooth from '../utils/ble/index.js'
import { STORAGE_KEY } from '../config/consts.js'
import Store from '../store/index'

export default class Printer extends Bluetooth {
  constructor(init = false, store) {
    super()
    this.onWatch = false
    this.store = store || Store
    this.runningList = []
    this.pendingList = []  // 当没有连接蓝牙打印机时的数据
    this.haveShowPrinterModel = false // 是否显示了未链接打印机弹框
    this.printFailNum = 0
    this.connectFail = false
    if (init) {
      // #ifdef APP-PLUS
      this.openBluetooth(() => {
        this.store.commit('SET_BLUETOOTH_STATUS', true)
        this.initBle()
        this.watchState()
      })
      // #endif
    }

  }

  watchState() {
    this.watchPinterState()
    this.watchPhoneBluetoothState()
    this.watchCharacteristicValueChange()
  }

  // 初始化连接过的蓝牙设备
  initBle() {
    this.store.commit('SYNC_SETTINGS')
    this.store.commit('SYNC_BLUETOOTH_INFO')
    let bleList = uni.getStorageSync(STORAGE_KEY.BLUETOOTH_INFO)
    this.openBluetooth((status) => {
      if (bleList && bleList.length > 0) {
        bindBle(bleList, 0)
      }
    })
    // 递归连接所有打印机
    let bindBle = (bleList, index = 0) => {
      let bleInfo = bleList[index]
      // debugger
      this.bind({
        ...bleInfo
      }, (res) => {
        index++
        if (bleList.length > index) bindBle(bleList, index)
        if (res.state) {
          this.store.commit('SET_BLUETOOTH_INFO', { ...bleInfo, connected: false })
          uni.showModal({
            content: `打印机${bleInfo.name}连接失败，请检查打印机状态`,
            cancelText: "不再使用",
            confirmText: "重新连接",
            success: (res) => {
              if (res.confirm) {
                uni.showLoading({ title: "重连中" })
                this.bind(bleInfo, (res) => {
                  uni.hideLoading();
                  if (!res.state) {
                    uni.showToast({
                      icon: "none",
                      title: "连接成功"
                    })
                  } else {
                    uni.showModal({
                      icon: "none",
                      content: "连接失败，请检查打印机或手机蓝牙状态是否正常",
                      success: ({ confirm, cancel }) => {
                        if (confirm) uni.navigateTo({ url: "/pages/printer/select" })
                      }
                    })
                  }
                })
              }
              if (res.cancel) {
                // 取消后从缓存中移除，以后不再自动链接
                this.store.commit('REMOVE_BLUETOOTH', bleInfo.deviceId)
              }
            }
          })
        } else {
          uni.showToast({
            title: `打印机${bleInfo.name}连接成功`,
            icon: "none"
          })
        }
      })
    }

  }

  printPendingData() {
    if (this.pendingList.length > 0) {
      this.printToAll(this.pendingList.shift())
      if (this.pendingList.length > 0) this.printPendingData()
    }
  }

  async bind(bleInfo, cb) {
    let { deviceId, name } = bleInfo
    let services = []
    let bleObj = {
      deviceId: deviceId,
      name: name,
      advertisServiceUUIDs: bleInfo.advertisServiceUUIDs,
      connected: false, // 连接状态
      services: bleInfo.services || [],
      readCharaterId: bleInfo.readCharaterId || "",
      readServiceId: bleInfo.readServiceId || "",
      writeCharaterId: bleInfo.writeCharaterId || "",
      writeServiceId: bleInfo.writeServiceId || "",
      notifyCharaterId: bleInfo.notifyCharaterId || "",
      notifyServiceId: bleInfo.notifyServiceId || "",
      indicateCharaterId: bleInfo.indicateCharaterId || "",
      indicateServiceId: bleInfo.indicateServiceId || "",
      buffList: bleInfo.buffList || [],
      running: false,
    }
    console.log('开始连接', name);
    this.createBLEConnection(deviceId).then(async res => {
      let servicesInfo = await this.getBLEDeviceServices(deviceId)
      services = servicesInfo.services.map(v => v.uuid)
      services = [...services, ...bleInfo.advertisServiceUUIDs]
      try {
        for (let index = 0; index < services.length; index++) {
          const serviceId = services[index];
          try {
            let characterist = await this.getBLEDeviceCharacteristics(deviceId, serviceId)
            for (let index = 0; index < characterist.characteristics.length; index++) {
              const value = characterist.characteristics[index];
              if (value.properties.read) {
                bleObj.readCharaterId = value.uuid
                bleObj.readServiceId = serviceId
              }
              if (value.properties.write) {
                bleObj.writeCharaterId = value.uuid
                bleObj.writeServiceId = serviceId
              }
              if (value.properties.notify) {
                bleObj.notifyCharaterId = value.uuid
                bleObj.notifyServiceId = serviceId
              }
              if (value.properties.indicate) {
                bleObj.indicateCharaterId = value.uuid
                bleObj.indicateServiceId = serviceId
              }
            }
          } catch (error) {
            console.log('获取characterist特征值失败', error);
          }
        }
      } catch (error) {
        console.log('获取services失败', error);
      }

      bleObj.services = services
      if (bleObj.writeCharaterId) {
        bleObj.connected = true
        console.log('连接成功', name);
        this.store.commit('SET_BLUETOOTH_INFO', bleObj)
        if (typeof cb == 'function') cb({ state: 0 })
      } else {
        console.log('连接失败', name, bleObj);
        this.checkHaveConnect(bleInfo.advertisServiceUUIDs, deviceId).then(res => {
          if (res) {
            uni.closeBLEConnection({
              deviceId
            })
          }
        })
        if (typeof cb == 'function') cb({ state: 1 })
      }
    }).catch(async e => {
      this.checkHaveConnect(bleInfo.advertisServiceUUIDs, deviceId).then(res => {
        if (res) {
          uni.closeBLEConnection({
            deviceId
          })
        }
      })
      if (typeof cb == 'function') cb({ state: 1, error: e })
    })
  }

  // 检查是否连接成功
  checkHaveConnect(advertisServiceUUIDs, deviceId) {
    return new Promise((resolve, reject) => {
      uni.getConnectedBluetoothDevices({
        services: advertisServiceUUIDs,
        success: res => {
          let deviceIds = (res.devices || []).map(v => v.deviceId)
          resolve(deviceIds.includes(deviceId))
        }
      })
    })

  }
  watchCharacteristicValueChange() {
    uni.onBLECharacteristicValueChange(function (res) {
      console.log('特征值发生变化', res);
    });
  }

  // 观察手机蓝牙状态
  watchPhoneBluetoothState() {
    this.onStateChange(res => {
      let bleStatus = this.store.getters.bleStatus
      if (res.available) {
        if (!bleStatus) {
          this.store.commit('SET_BLUETOOTH_STATUS', true)
          this.initBle()
        }
      } else {
        if (bleStatus) {
          uni.showModal({
            content: "蓝牙已断开，请检查蓝牙状态是否正常",
            showCancel: false,
            confirmText: "确定",
            success: (res) => {
              if (res.confirm) this.openPhoneBluetooth()
            }
          })
          this.store.commit('SET_BLUETOOTH_STATUS', false)
        }
      }
    })
  }


  async getBleDetailData(deviceId) {
    let bleObj = {
      readCharaterId: "",
      readServiceId: "",
      writeCharaterId: "",
      writeServiceId: "",
      notifyCharaterId: "",
      notifyServiceId: "",
      indicateCharaterId: "",
      indicateServiceId: "",
    }
    let servicesInfo = await this.getBLEDeviceServices(deviceId)
    let services = servicesInfo.services.map(v => v.uuid)
    if (services.length == 0) {
      this.getBleDetailData(deviceId)
    } else {
      try {
        for (let index = 0; index < services.length; index++) {
          const service = services[index];
          try {
            if (service) {
              let characterist = await this.getBLEDeviceCharacteristics(deviceId, service)
              for (let index = 0; index < characterist.characteristics.length; index++) {
                const value = characterist.characteristics[index];
                if (value.properties.read) {
                  bleObj.readCharaterId = value.uuid
                  bleObj.readServiceId = service
                }
                if (value.properties.write) {
                  bleObj.writeCharaterId = value.uuid
                  bleObj.writeServiceId = service
                }
                if (value.properties.notify) {
                  bleObj.notifyCharaterId = value.uuid
                  bleObj.notifyServiceId = service
                }
                if (value.properties.indicate) {
                  bleObj.indicateCharaterId = value.uuid
                  bleObj.indicateServiceId = service
                }
              }
            }
          } catch (error) {
            console.log('获取characterist特征值失败', error);
          }
        }
      } catch (error) {
        console.log('获取services失败', error);
      }
      console.log('bleObj', bleObj);
    }
    // this.store.commit('SET_BLUETOOTH_INFO', bleObj)
  }

  reconnect(bleInfo, cb, connectTime = 0) {
    let maxTime = 10
    this.bind(bleInfo, res => {
      connectTime++
      console.log('connectTime', connectTime);
      if (res.state) {
        if (connectTime >= maxTime) {
          if (typeof cb == 'function') cb({ state: 1 })
        } else {
          this.reconnect(bleInfo, cb, connectTime)
        }
      } else {
        if (typeof cb == 'function') cb({ state: 0 })
      }
    })
  }
  //观察打印机状态 
  watchPinterState() {

    uni.onBLEConnectionStateChange((res) => {
      // 该方法回调中可以用于处理连接意外断开等异常情况
      if (res.connected) {
        console.log('打印机连接成功', res);
      } else {
        console.log('打印机连接断开', res);
        let bleList = this.store.state.printer.bleList
        let bleInfo = bleList.find(item => item.deviceId == res.deviceId) // 是否为主动断开连接
        console.log("bleInfo", bleInfo);

        // 如果bleList中没有该蓝牙则为主动关闭
        let isActive = !bleInfo || !bleInfo.connect ? true : false
        // 意外断开时，重新连接
        if (!isActive) {
          this.store.commit('SET_BLUETOOTH_INFO', { ...bleInfo, connected: false })
          if (!this.haveShowPrinterModel) {
            this.haveShowPrinterModel = true
            uni.showModal({
              content: `打印机${bleInfo.name}异常断开,是否重新连接`,
              confirmText: "是",
              cancelText: "否",
              success: ({ confirm, cancel }) => {
                this.haveShowPrinterModel = false
                if (confirm) {
                  uni.showLoading({ title: "重连中" })
                  this.bind(bleInfo, (res) => {
                    uni.hideLoading();
                    if (!res.state) {
                      uni.showToast({
                        icon: "none",
                        title: "连接成功"
                      })
                    } else {
                      uni.showModal({
                        icon: "none",
                        content: "连接失败，请检查打印机或手机蓝牙状态是否正常",
                        success: ({ confirm, cancel }) => {
                          if (confirm) uni.navigateTo({ url: "/pages/printer/select" })
                        }
                      })
                    }
                  })
                }
                if (cancel) {
                  // 取消后从缓存中移除，以后不再自动链接
                  // this.store.commit('REMOVE_BLUETOOTH', bleInfo.deviceId)
                }
              }
            })
          }

        }
      }
    })
  }

  // 让所有打印机打印
  printToAll(buff, cb, bleList, settings) {

    bleList = bleList || this.store.state.printer.bleList
    settings = settings || this.store.getters.settings

    if (bleList.length == 0) {
      this.pendingList.push(buff) // 当没有链接蓝牙时，保存起来
      if (!this.haveShowPrinterModel) {
        this.haveShowPrinterModel = true
        uni.showModal({
          title: "提示",
          content: "打印机未连接，是否前往设置?",
          confirmText: "前往设置",
          cancelText: "否",
          success: (res) => {
            this.haveShowPrinterModel = false
            if (res.confirm) {
              uni.navigateTo({
                url: '/pages/printer/select'
              })
            }
            if (res.cancel) {

            }
          }
        })
      }
    }

    /**
     * 打印
     * @param {*} bleInfo 蓝牙设备信息
     * @param {*} buffData 打印数据
     * @param {*} iscb 是否为内部调用
     */
    let printBuff = async (bleInfo, buffData, iscb) => {
      // 判断该打印机是否在运行，如果在运行则返回
      let hasBle = this.runningList.includes(bleInfo.deviceId)
      if (!hasBle) {
        this.runningList.push(bleInfo.deviceId)
      } else {
        if (!iscb) return
      }
      let bleObj = {
        advertisServiceUUIDs: bleInfo.advertisServiceUUIDs,
        ...bleInfo
      }
      this.print({
        deviceId: bleInfo.deviceId,
        writeServiceId: bleInfo.writeServiceId || bleObj.writeServiceId,
        writeCharaterId: bleInfo.writeCharaterId || bleObj.writeCharaterId,
        buff: buffData,
        num: settings.number,
        success: () => {
          this.printFailNum = 0
          this.store.commit('DELETE_BUFF_FROM_PRINTER', bleInfo.deviceId)
          // 如果还有则继续打印，反之将打印机从运行状态删除
          let printerInfo = this.store.state.printer.bleList.find(v => v.deviceId == bleInfo.deviceId)
          let buffList = printerInfo && printerInfo.buffList
          console.log('打印完成', buffList.length);
          if (buffList.length > 0) {
            setTimeout(() => {
              printBuff(bleInfo, buffList[0], true)
            }, 100);
          } else {
            let index = this.runningList.indexOf(bleInfo.deviceId)
            this.runningList.splice(index, 1)
          }
        },
        fail: e => {
          console.log('打印失败', e);
          this.store.commit('DELETE_BUFF_FROM_PRINTER', bleInfo.deviceId)
          // 如果还有则继续打印，反之将打印机从运行状态删除
          let printerInfo = this.store.state.printer.bleList.find(v => v.deviceId == bleInfo.deviceId)
          let buffList = printerInfo && printerInfo.buffList
          if (buffList.length > 0) {
            setTimeout(() => {
              printBuff(bleInfo, buffList[0], true)
            }, 100);
          } else {
            let index = this.runningList.indexOf(bleInfo.deviceId)
            this.runningList.splice(index, 1)
          }
          // 当打印错误
          if (!this.haveShowPrinterModel) {
            uni.showModal({
              title: "提示",
              content: `打印失败，请检查打印机${bleInfo.name}链接状态`,
              success: (res) => {
                this.haveShowPrinterModel = false
                if (res.confirm) {
                  uni.navigateTo({
                    url: '/pages/printer/select'
                  })
                }
              }
            })
          }
          if (typeof cb == 'function') cb({ state: 1, error: e })
        }
      });
    }

    bleList.forEach(ble => {
      // 向打印机添加待打印数据
      this.store.commit('ADD_BUFF_TO_PRINTER', { buff: buff, deviceId: ble.deviceId })
      printBuff(ble, buff)
    });

  }
}
